#include "VistaQt.h"
#include "about.h"
#include "saveas.h"
#include <qpen.h>
#include <algorithm>
#include <iostream>
#include <limits.h>
#include <qt3/qimage.h>

Lienzo::Lienzo()
{

}

void
Ventana::pintaPunto(int x, int y)
{
    Punto* p = new Punto(x,y);
    p->SetColor(spinBoxRojo->value()/255.0, spinBoxVerde->value()/255.0, spinBoxAzul->value()/255.0);
    su_modelo -> figuras.push_back(p);
}

void
Ventana::pintaLinea(const QPoint& p, int n)
{
    Punto p1(p.x()-REL_WIDTH, p.y()-REL_HEIGHT);

    Linea* l;

    if(n == 0)
    {
        l = new Linea();
        l->SetColor(spinBoxRojo->value()/255.0, spinBoxVerde->value()/255.0, spinBoxAzul->value()/255.0);
        l -> SetX(p1.GetX()); l -> SetY(p1.GetY());
        su_modelo -> figuras.push_back(l);
    }
    else if(n == 1)
    {
        l = (Linea*) su_modelo -> figuras.back();
        l -> SetQ(p1);
    }
}

void
Ventana::pintaCirc(const QPoint& p, int n)
{
    Punto p1(p.x()-REL_WIDTH, p.y()-REL_HEIGHT);

    Circulo* c;

    if(n == 0)
    {
        c = new Circulo();
        c->SetColor(spinBoxRojo->value()/255.0, spinBoxVerde->value()/255.0, spinBoxAzul->value()/255.0);
        c -> SetX(p1.GetX()); c -> SetY(p1.GetY());
        su_modelo -> figuras.push_back(c);
    }
    else if(n == 1)
    {
        c = (Circulo*) su_modelo -> figuras.back();
        c -> SetRadio(abs(c -> GetX()-p1.GetX()));
    }
}

void
Ventana::pintaRec(const QPoint& p, int n, bool selectionRect)
{
    Punto p1(p.x()-REL_WIDTH, p.y()-REL_HEIGHT);

    Rectangulo* r;

    if(n == 0)
    {
        r = new Rectangulo();
        r->SetColor(spinBoxRojo->value()/255.0, spinBoxVerde->value()/255.0, spinBoxAzul->value()/255.0);
        if(selectionRect)
            r -> setSelectionRect();
        r -> SetX(p1.GetX()); r -> SetY(p1.GetY());
        su_modelo -> figuras.push_back(r);
    }
    else if(n == 1)
    {
        r = (Rectangulo*) su_modelo -> figuras.back();
        r -> SetAlto(p1.GetY() - r -> GetY());
        r -> SetAncho(p1.GetX() - r -> GetX());
    }
}

void
Ventana::pintaTri(const QPoint& p, int n)
{
    Punto p1(p.x()-REL_WIDTH, p.y()-REL_HEIGHT);

    Triangulo* t;
    int dX = 0;
    int maxX = 0, maxY = 0;

    if(n == 0)
    {
        t = new Triangulo();
        t->SetColor(spinBoxRojo->value()/255.0, spinBoxVerde->value()/255.0, spinBoxAzul->value()/255.0);
        t -> SetX(p1.GetX()); t -> SetY(p1.GetY());
        su_modelo -> figuras.push_back(t);
    }
    else if(n == 1)
    {
        t = (Triangulo*) su_modelo -> figuras.back();
        t -> SetP(1, p1.GetX(), p1.GetY());
        
        dX = abs(t -> GetP(1).GetX() - t -> GetX());

        maxX = max(t->GetP(1).GetX(), t -> GetX());
        maxY = max(t->GetP(1).GetY(), t -> GetY());
        
        t -> SetP(2, maxX-2*dX, maxY);
    }
}

void Ventana::pintaImage(const QPoint& p) {
    QFileDialog *fd = new QFileDialog();
    if ( fd->exec() == QDialog::Accepted ) {
        QString fileName = fd->selectedFile();

        ImagenQt *img = new ImagenQt(p.x()-REL_WIDTH, p.y()-REL_HEIGHT, fileName);
        su_modelo->figuras.push_back(img);
    }
}

Ventana::Ventana()
{
    drawArea = new Lienzo(this -> frame5_2, TRUE);
    botones = new bool[7];
    historial_actual = 0;
    
    QWidget::connect((QObject*) botonPunto, SIGNAL(pressed()), SLOT(clickPunto()));
    QWidget::connect((QObject*) botonLinea, SIGNAL(pressed()), SLOT(clickLinea()));
    QWidget::connect((QObject*) botonRec, SIGNAL(pressed()), SLOT(clickRec()));
    QWidget::connect((QObject*) botonTri, SIGNAL(pressed()), SLOT(clickTri()));
    QWidget::connect((QObject*) botonCirc, SIGNAL(pressed()), SLOT(clickCirc()));
    QWidget::connect((QObject*) botonImage, SIGNAL(pressed()), SLOT(clickImage()));

    QWidget::connect((QObject*) botonSelect, SIGNAL(pressed()), SLOT(clickSelect()));
    QWidget::connect((QObject*) botonCopy, SIGNAL(pressed()), SLOT(clickCopy()));
    QWidget::connect((QObject*) botonPaste, SIGNAL(pressed()), SLOT(clickPaste()));
    QWidget::connect((QObject*) botonDup, SIGNAL(pressed()), SLOT(clickDup()));
    QWidget::connect((QObject*) botonCut, SIGNAL(pressed()), SLOT(clickCut()));
    QWidget::connect((QObject*) botonDelete, SIGNAL(pressed()), SLOT(clickDelete()));
    QWidget::connect((QObject*) botonGroup, SIGNAL(pressed()), SLOT(clickGroup()));
    QWidget::connect((QObject*) botonUngroup, SIGNAL(pressed()), SLOT(clickUngroup()));
    QWidget::connect((QObject*) botonUndo, SIGNAL(pressed()), SLOT(clickUndo()));
    QWidget::connect((QObject*) botonRedo, SIGNAL(pressed()), SLOT(clickRedo()));
    
    QWidget::connect((QObject*) editCopyAction, SIGNAL(activated()), SLOT(clickCopy()));
    QWidget::connect((QObject*) editCutAction, SIGNAL(activated()), SLOT(clickCut()));
    QWidget::connect((QObject*) editPasteAction, SIGNAL(activated()), SLOT(clickPaste()));

    QWidget::connect((QObject*) fileNewAction, SIGNAL(activated()), SLOT(newFile()));
    QWidget::connect((QObject*) fileSaveAction, SIGNAL(activated()), SLOT(guardar()));
    QWidget::connect((QObject*) fileOpenAction, SIGNAL(activated()), SLOT(abrir()));
    QWidget::connect((QObject*) fileSaveAsAction, SIGNAL(activated()), SLOT(openSaveAs()));
    QWidget::connect((QObject*) helpAboutAction, SIGNAL(activated()), SLOT(openAbout()));
    QWidget::connect((QObject*) fileExitAction, SIGNAL(activated()), SLOT(exit()));
    QWidget::connect(spinBoxAutoSave, SIGNAL(valueChanged(int)), SLOT(setSpinBox(int)));

    timer = new QTimer(this);
    connect((QObject*) timer, SIGNAL(timeout()), SLOT(guardar()));
}

void Ventana::exit() {
    qApp->quit();
}

void Ventana::newFile() {
    su_modelo->vaciarFiguras();
    pinta();
}

void
Ventana::openAbout()
{
    Form2* f2 = new Form2();
    f2->show();
}

void
Ventana::openSaveAs()
{
    SaveAs* save = new SaveAs(this);
    save->show();
}

void
Ventana::setSpinBox(int v)
{
    if(v != 0)
        timer->start(v*1000);
    else
        timer->stop();
}

void Ventana::cargarImagenes() {
    vector<ImagenQt*> imagenes_nuevas;
    for(vector<Primitiva*>::iterator it = su_modelo->figuras.begin(); it != su_modelo->figuras.end();) {
        Imagen* pImagen = dynamic_cast<Imagen*>( *it );

        if(pImagen) {
            ImagenQt *pImagenQt = new ImagenQt(pImagen->GetX()-REL_WIDTH, pImagen->GetY()-REL_HEIGHT, pImagen->GetFileName());
            imagenes_nuevas.push_back(pImagenQt);
        }

        if(pImagen)
            it = su_modelo->figuras.erase(it);
        else
            it++;
    }

    for(int i = 0; i < (signed)imagenes_nuevas.size(); i++)
        su_modelo->figuras.push_back(imagenes_nuevas[i]);
}

void
Ventana::abrir()
{
    QFileDialog *fd = new QFileDialog();
    if ( fd->exec() == QDialog::Accepted ) {
        QString fileName = fd->selectedFile();

        su_modelo->cargarFichero(fileName);
        cargarImagenes();
        pinta();
    }
}

void
Ventana::guardar()
{
    su_modelo->guardarAFichero(su_modelo->figuras, "figuras.txt");
}

void Ventana::pinta(bool end)
{
    QPainter* p = drawArea;

    /* Limpia el lienzo */
    frame5_2->repaint(this->frame5_2->frameRect(),true);

    pintaVector(su_modelo->figuras,p, end);
    
    Actualizar();
}

void
Ventana::pintaVector(vector<Primitiva*> v, QPainter* p, bool end)
{
    QPen selectionPen(QColor(0,0,255),2,Qt::DashLine);
    
    for(int i = 0; i < (signed)v.size(); i++)
    {
        QPen pen(QColor(v[i]->GetRed()*255,v[i]->GetGreen()*255,v[i]->GetBlue()*255), 2);
        p -> setPen(pen);

        Punto* p_subclass = dynamic_cast<Punto*>( v[i] );
        Linea* l_subclass = dynamic_cast<Linea*>( v[i] );
        Rectangulo* r_subclass = dynamic_cast<Rectangulo*>( v[i] );
        Triangulo* t_subclass = dynamic_cast<Triangulo*>( v[i] );
        Circulo* c_subclass = dynamic_cast<Circulo*>( v[i] );
        Conjunto* cj_subclass = dynamic_cast<Conjunto*>( v[i] );
        ImagenQt* img_subclass = dynamic_cast<ImagenQt*>( v[i] );

        if(p_subclass)
            p -> drawPoint(p_subclass -> GetX(), p_subclass -> GetY());
        else if(l_subclass)
        {
            if(l_subclass->GetGrados() != 0)
            {
                int d = sqrt(pow(l_subclass->GetQ().GetX()-l_subclass->GetX(),2)+pow(l_subclass->GetQ().GetY()-l_subclass->GetY(),2));
                int alpha = l_subclass->GetGrados()/90;
                Punto p(l_subclass -> GetX()+d*cos(alpha), l_subclass -> GetY()-d*sin(alpha));
                l_subclass->SetQ(p);
            }

            p -> drawLine(l_subclass -> GetX(),  l_subclass -> GetY(),
            l_subclass -> GetQ().GetX(), l_subclass -> GetQ().GetY());
        }
        else if(r_subclass)
        {
            if(r_subclass->IsSelectionRect())
                p->setPen(selectionPen);

            int x=r_subclass->GetX();
            int y=r_subclass->GetY();
            int w = r_subclass->GetAncho();
            int h = r_subclass->GetAlto();
            float alpha = r_subclass -> GetGrados() / 90;

            //cout << "Height: " << h << " vs y3-y: " << y+h*cos(alpha)-y << endl;
            QPointArray rectPoints(4);
            // Top Left
            rectPoints.setPoint(0,x,y);
            // Top Right
            rectPoints.setPoint(1,x+w*cos(alpha),y-w*sin(alpha));
            // Bottom right
            rectPoints.setPoint(2,x+h*sin(alpha)+w*cos(alpha),y-w*sin(alpha)+h*cos(alpha));
            // Bottom left
            rectPoints.setPoint(3,x+h*sin(alpha),y+h*cos(alpha));

            p->drawPolygon(rectPoints);
            //p -> drawRect(r_subclass -> GetX(), r_subclass -> GetY(), r_subclass -> GetAncho(), r_subclass -> GetAlto());

            if(end && r_subclass->IsSelectionRect())
                su_modelo->figuras.erase(su_modelo->figuras.begin()+i);
        }
        else if(t_subclass)
        {
            QPointArray a(3);
            a.setPoint(0, t_subclass -> GetX(), t_subclass -> GetY());
            int alpha = t_subclass->GetGrados() / 120;
            int x = t_subclass->GetX();
            int y = t_subclass->GetY();

            int w2 = t_subclass -> GetP(1).GetX()-x;
            int h2 = t_subclass -> GetP(1).GetY()-y;

            int w3 = t_subclass -> GetP(2).GetX()-x;
            int h3 = t_subclass -> GetP(2).GetY()-y;

            //long int r = sqrt(pow(abs(p3x-p2x),2)+pow(abs(p3y-p2y),2));

            int aux = 0;
            if(t_subclass->GetGrados() != 0)
            {
                if(w2 > 0)
                {
                    if(h2 <= 0)
                    {
                        aux = w2;
                        w2 = h2;
                        h2 = aux;
                    }
                }
                else
                {
                    if(h2 >= 0)
                    {
                        aux = h2;
                        h2 = w2;
                        w2 = aux;
                    }
                }
                
                if(w3 > 0)
                {
                    if(h3 <= 0)
                    {
                        aux = w3;
                        w3 = h3;
                        h3 = aux;
                    }
                }
                else
                {
                    if(h3 >= 0)
                    {
                        aux = h3;
                        h3 = w3;
                        w3 = aux;
                    }
                }
                
                a.setPoint(1, x+h2*sin(alpha)+w2*cos(alpha),y-w2*sin(alpha)+h2*cos(alpha));
                a.setPoint(2, x+h3*sin(alpha)+w3*cos(alpha),y-w3*sin(alpha)+h3*cos(alpha));
            }
            else
            {
                a.setPoint(1, t_subclass->GetP(1).GetX(), t_subclass->GetP(1).GetY());
                a.setPoint(2, t_subclass->GetP(2).GetX(), t_subclass->GetP(2).GetY());
            }
            p -> drawPolygon(a);
        }
        else if(c_subclass)
            p -> drawEllipse(c_subclass -> GetX(), c_subclass -> GetY(), c_subclass -> GetRadio(), c_subclass -> GetRadio());
        else if(cj_subclass)
            pintaVector(cj_subclass->GetComponentes(),p, end);
        else if(img_subclass) {
            QPoint img_point(img_subclass->GetX(), img_subclass->GetY());
            p->drawImage(img_point, img_subclass->GetImage());
        }

        p_subclass = NULL; l_subclass = NULL; r_subclass = NULL;
        t_subclass = NULL; c_subclass = NULL;
    }
}

void
Ventana::mouseMoveEvent(QMouseEvent* e)
{
    QPoint p(e -> pos());

    if(!su_modelo->figuras.empty())
    {
        Linea* l_subclass = dynamic_cast<Linea*>( su_modelo -> figuras.back() );
        Rectangulo* r_subclass = dynamic_cast<Rectangulo*>( su_modelo -> figuras.back() );
        Triangulo* t_subclass = dynamic_cast<Triangulo*>( su_modelo -> figuras.back() );
        Circulo* c_subclass = dynamic_cast<Circulo*>( su_modelo -> figuras.back() );

        if(l_subclass && MODE == DRAW)
        {
            pintaLinea(p,1);
            pinta();
        }
        else if(r_subclass && (MODE == DRAW || r_subclass->IsSelectionRect()))
        {
            pintaRec(p,1, r_subclass->IsSelectionRect());
            pinta();
        }
        else if(t_subclass && MODE == DRAW)
        {
            pintaTri(p,1);
            pinta();
        }
        else if(c_subclass && MODE == DRAW)
        {
            pintaCirc(p,1);
            pinta();
        }
        else if(MODE == EDIT && !su_modelo->figurasSeleccionadas.empty())
        {
            for(int i = 0; i < (signed) su_modelo->figurasSeleccionadas.size(); i++)
            {
                // Se requiere saber la subclase que es para mover X vértices
                Punto* p_subclass = dynamic_cast<Punto*>( su_modelo -> figurasSeleccionadas[i] );
                Linea* l_subclass = dynamic_cast<Linea*>( su_modelo -> figurasSeleccionadas[i] );
                Rectangulo* r_subclass = dynamic_cast<Rectangulo*>( su_modelo -> figurasSeleccionadas[i] );
                Triangulo* t_subclass = dynamic_cast<Triangulo*>( su_modelo -> figurasSeleccionadas[i] );
                Circulo* c_subclass = dynamic_cast<Circulo*>( su_modelo -> figurasSeleccionadas[i] );
                Conjunto* cj_subclass = dynamic_cast<Conjunto*>( su_modelo -> figurasSeleccionadas[i] );
                ImagenQt* img_subclass = dynamic_cast<ImagenQt*>( su_modelo -> figurasSeleccionadas[i] );

                if(p_subclass)
                    su_modelo->figurasSeleccionadas[i]->Move(e->pos().x()-move_ini_x,e->pos().y()-move_ini_y);
                else if(l_subclass)
                    su_modelo->figurasSeleccionadas[i]->Move(e->pos().x()-move_ini_x,e->pos().y()-move_ini_y);
                else if(r_subclass)
                    su_modelo->figurasSeleccionadas[i]->Move(e->pos().x()-move_ini_x,e->pos().y()-move_ini_y);
                else if(t_subclass)
                    su_modelo->figurasSeleccionadas[i]->Move(e->pos().x()-move_ini_x,e->pos().y()-move_ini_y);
                else if(c_subclass)
                    su_modelo->figurasSeleccionadas[i]->Move(e->pos().x()-move_ini_x,e->pos().y()-move_ini_y);
                else if(cj_subclass)
                    su_modelo->figurasSeleccionadas[i]->Move(e->pos().x()-move_ini_x,e->pos().y()-move_ini_y);
                else if(img_subclass)
                    su_modelo->figurasSeleccionadas[i]->Move(e->pos().x()-move_ini_x,e->pos().y()-move_ini_y);
            }

            pinta();

            move_ini_x = e->pos().x();
            move_ini_y = e->pos().y();
        }
    }
}

void
Ventana::mousePressEvent(QMouseEvent* e)
{
    QPoint p(e -> pos());
   
    if((frame5_2 -> contentsRect()).contains(e->pos()))
    {
        if(botones[0] && e->button() == 1 && MODE == DRAW)
        {
            pintaPunto(e -> x()-REL_WIDTH, e-> y()-REL_HEIGHT);
            pinta();
        }
        else if(botones[1] && e->button() == 1 && MODE == DRAW)
            pintaLinea(p,0);
        else if(botones[2] && e->button() == 1 && MODE == DRAW)
            pintaRec(p,0, false);
        else if(botones[3] && e->button() == 1 && MODE == DRAW)
            pintaTri(p,0);
        else if(botones[4] && e->button() == 1 && MODE == DRAW)
            pintaCirc(p,0);
        else if(botones[6] && e->button() == 1 && MODE == DRAW) {
            pintaImage(p);
            pinta();
        }
        else if(((botones[5] && e->button() == 1) || e->button() == 2) && !su_modelo->figuras.empty())
            pintaRec(p,0, true);
        else if(e->button() == 1 && !su_modelo->figurasSeleccionadas.empty()) {
            move_ini_x = e->pos().x();
            move_ini_y = e->pos().y();
        }
    }
}

void
Ventana::mouseReleaseEvent(QMouseEvent* e)
{
    QRect* area;
    su_modelo->figurasSeleccionadas.clear();
    if(((e->button()==1 && botones[5]) || e->button() == 2) && !su_modelo->figuras.empty())
    {
        if(botones[5]) botones[5] = false;
        Rectangulo* r = (Rectangulo*) su_modelo->figuras.back();
        if(r->GetAncho() < 0)
            area = new QRect(r->GetX()+r->GetAncho(),r->GetY()+r->GetAlto(),r->GetAncho()*(-1),r->GetAlto()*(-1));
        else
            area = new QRect(r->GetX(),r->GetY(),r->GetAncho(),r->GetAlto());

        for(int i = 0; i < (signed)su_modelo -> figuras.size()-1; i++)
        {
            Punto* p_subclass = dynamic_cast<Punto*>( su_modelo -> figuras[i] );
            Linea* l_subclass = dynamic_cast<Linea*>( su_modelo -> figuras[i] );
            Rectangulo* r_subclass = dynamic_cast<Rectangulo*>( su_modelo -> figuras[i] );
            Triangulo* t_subclass = dynamic_cast<Triangulo*>( su_modelo -> figuras[i] );
            Circulo* c_subclass = dynamic_cast<Circulo*>( su_modelo -> figuras[i] );
            Conjunto* cj_subclass = dynamic_cast<Conjunto*>( su_modelo -> figuras[i] );
            ImagenQt* img_subclass = dynamic_cast<ImagenQt*>( su_modelo -> figuras[i] );

            if(p_subclass && containsPunto(*area,*p_subclass))
                su_modelo->figurasSeleccionadas.push_back(p_subclass);
            else if(l_subclass && containsLinea(*area,*l_subclass))
                su_modelo->figurasSeleccionadas.push_back(l_subclass);
            else if(r_subclass && containsRect(*area,*r_subclass))
                su_modelo->figurasSeleccionadas.push_back(r_subclass);
            else if(t_subclass && containsTri(*area,*t_subclass))
                su_modelo->figurasSeleccionadas.push_back(t_subclass);
            else if(c_subclass && containsCirc(*area,*c_subclass))
                su_modelo->figurasSeleccionadas.push_back(c_subclass);
            else if(cj_subclass && containsConjunto(*area,*cj_subclass))
                su_modelo->figurasSeleccionadas.push_back(cj_subclass);
            else if(img_subclass && containsImagen(*area, *img_subclass))
                su_modelo->figurasSeleccionadas.push_back(img_subclass);
        }
        pinta(true);
    }

    if(historial_actual != (signed)historial.size() - 1) {
        while(historial_actual != (signed)historial.size() - 1) {
            historial.pop_back();
        }
    }

    Historial *nuevo = new Historial(su_modelo);
    historial.push_back(nuevo);
    historial_actual = historial.size() - 1;

    MODE = EDIT;
    labelState->setText("Modo de edicion");
}

void
Ventana::keyReleaseEvent(QKeyEvent* e)
{
    if(e -> key() == Key_Shift || e->key() == Key_Control)
        su_modelo->figurasSeleccionadas.clear();
}

bool
Ventana::containsConjunto(const QRect& area, const Conjunto& c)
{
    bool contenido = true;

    for(int i = 0; i < (signed) c.GetComponentes().size(); i++)
    {
        Punto* p_subclass = dynamic_cast<Punto*>( c.GetComponentes()[i] );
        Linea* l_subclass = dynamic_cast<Linea*>( c.GetComponentes()[i] );
        Rectangulo* r_subclass = dynamic_cast<Rectangulo*>( c.GetComponentes()[i] );
        Triangulo* t_subclass = dynamic_cast<Triangulo*>( c.GetComponentes()[i] );
        Circulo* c_subclass = dynamic_cast<Circulo*>( c.GetComponentes()[i] );
        ImagenQt* img_subclass = dynamic_cast<ImagenQt*>( c.GetComponentes()[i] );

        if(p_subclass) {
            if(!containsPunto(area,*p_subclass)) contenido=false;
        } else if(l_subclass) {
            if(!containsLinea(area,*l_subclass)) contenido=false;
        } else if(r_subclass) {
            if(!containsRect(area,*r_subclass)) contenido=false;
        } else if(t_subclass) {
            if(!containsTri(area,*t_subclass)) contenido=false;
        } else if(c_subclass) {
            if(!containsCirc(area,*c_subclass)) contenido=false;
        } else if(img_subclass) {
            if(!containsImagen(area, *img_subclass)) contenido = false;
        }
    }

    return contenido;
}

bool
Ventana::containsPunto(const QRect& area, const Punto& p)
{
    bool contenido = false;
    QPoint point(p.GetX(),p.GetY());

    if(area.contains(point))
        contenido = true;
    
    return contenido;
}

bool
Ventana::containsLinea(const QRect& area, const Linea& linea)
{
    bool contenido = false;
    QPoint p(linea.GetX(), linea.GetY());
    QPoint q(linea.GetQ().GetX(), linea.GetQ().GetY());

    if(area.contains(p) && area.contains(q))
        contenido = true;
    
    return contenido;
}

bool
Ventana::containsRect(const QRect& area, const Rectangulo& rect)
{
    bool contenido = false;

    int x = rect.GetX();
    int y = rect.GetY();
    int w = rect.GetAncho();
    int h = rect.GetAlto();
    float alpha = rect.GetGrados() / 90;
    // Top Left
    QPoint tl(x,y);
    // Top Right
    QPoint tr(x+w*cos(alpha),y-w*sin(alpha));
    // Bottom right
    QPoint br(x+h*sin(alpha)+w*cos(alpha),y-w*sin(alpha)+h*cos(alpha));
    // Bottom left
    QPoint bl(x+h*sin(alpha),y+h*cos(alpha));

    if(area.contains(tl) && area.contains(tr) && area.contains(br) && area.contains(bl))
        contenido = true;

    return contenido;
}

bool
Ventana::containsCirc(const QRect& area, const Circulo& circ)
{
    bool contenido = false;

    QRect rectangulo(circ.GetX(),circ.GetY(),circ.GetRadio(),circ.GetRadio());
    
    if(area.contains(rectangulo))
        contenido = true;

    return contenido;
}

bool
Ventana::containsTri(const QRect& area, const Triangulo& tri)
{
    bool contenido = false;

    int alpha = tri.GetGrados() / 120;
    int x = tri.GetX();
    int y = tri.GetY();

    int w2 = tri.GetP(1).GetX()-x;
    int h2 = tri.GetP(1).GetY()-y;

    int w3 = tri.GetP(2).GetX()-x;
    int h3 = tri.GetP(2).GetY()-y;

    int aux = 0;
    if(tri.GetGrados() != 0)
    {
        if(w2 > 0)
        {
            if(h2 <= 0)
            {
                aux = w2;
                w2 = h2;
                h2 = aux;
            }
        }
        else
        {
            if(h2 >= 0)
            {
                aux = h2;
                h2 = w2;
                w2 = aux;
            }
        }

        if(w3 > 0)
        {
            if(h3 <= 0)
            {
                aux = w3;
                w3 = h3;
                h3 = aux;
            }
        }
        else
        {
            if(h3 >= 0)
            {
                aux = h3;
                h3 = w3;
                w3 = aux;
            }
        }
    }

    int dX = abs(tri.GetP(1).GetX() - tri.GetX());
    int dY = abs(tri.GetP(1).GetY() - tri.GetY());
    int minX = min(min(x+h2*sin(alpha)+w2*cos(alpha), (double)tri.GetX()), (int)x+h3*sin(alpha)+w3*cos(alpha));
    int minY = min(min(y-w2*sin(alpha)+h2*cos(alpha), (double)tri.GetY()), (int)y-w3*sin(alpha)+h3*cos(alpha));

    QRect rectangulo(minX,minY,2*dX,dY);
        
    if(area.contains(rectangulo))
        contenido = true;

    return contenido;
}

bool
Ventana::containsImagen(const QRect& area, const ImagenQt& img)
{
    bool contenido = false;

    int x = img.GetX();
    int y = img.GetY();
    int w = img.GetImage().width();
    int h = img.GetImage().height();
    float alpha = img.GetGrados() / 90;
    // Top Left
    QPoint tl(x,y);
    // Top Right
    QPoint tr(x+w*cos(alpha),y-w*sin(alpha));
    // Bottom right
    QPoint br(x+h*sin(alpha)+w*cos(alpha),y-w*sin(alpha)+h*cos(alpha));
    // Bottom left
    QPoint bl(x+h*sin(alpha),y+h*cos(alpha));

    if(area.contains(tl) && area.contains(tr) && area.contains(br) && area.contains(bl))
        contenido = true;

    return contenido;
}

void
Ventana::clickCopy()
{
    if(!su_modelo->figurasSeleccionadas.empty())
    {
        vector<Primitiva*>::iterator it;
        for(it = su_modelo->figurasSeleccionadas.begin(); it != su_modelo->figurasSeleccionadas.end();it++)
        {
            su_modelo->portapapeles.push_back(*it);
        }
    }
}

void
Ventana::clickCut()
{
    clickCopy();
    clickDelete();
}

void
Ventana::clickPaste()
{
    if(!su_modelo->portapapeles.empty())
    {
        int minX = 10000,minY = 10000;
        int maxX=0,maxY=0;
        vector<Primitiva*>::iterator it;
        su_modelo->figurasSeleccionadas.clear();

        for(it = su_modelo->portapapeles.begin(); it != su_modelo->portapapeles.end();it++)
        {
            Punto* p_subclass = dynamic_cast<Punto*>(*it);
            Linea* l_subclass = dynamic_cast<Linea*>(*it);
            Rectangulo* r_subclass = dynamic_cast<Rectangulo*>(*it);
            Triangulo* t_subclass = dynamic_cast<Triangulo*>(*it);
            Circulo* c_subclass = dynamic_cast<Circulo*>(*it);
            Conjunto* cj_subclass = dynamic_cast<Conjunto*>(*it);
            ImagenQt* img_subclass = dynamic_cast<ImagenQt*>(*it);

            if(p_subclass)
            {
                Punto* p1 = new Punto(p_subclass->GetX()+10,p_subclass->GetY()+10);

                su_modelo->figuras.push_back(p1);

                p_subclass = (Punto*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(p_subclass);
                
                minX = min(p_subclass->GetX(), minX);
                minY = min(p_subclass->GetY(), minY);
                maxX = max(p_subclass->GetX(), maxX);
                maxY = max(p_subclass->GetY(), maxY);
            }
            else if(l_subclass)
            {
                Linea* l = new Linea(*l_subclass);
                l -> SetX(l->GetX()+10);
                l -> SetY(l->GetY()+10);
                Punto p(l->GetQ().GetX()+10,l->GetQ().GetY()+10);
                l -> SetQ(p);
                
                su_modelo->figuras.push_back(l);

                l_subclass = (Linea*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(l_subclass);
                
                minX = min(min(l_subclass->GetX(), l_subclass->GetQ().GetX()),minX);
                minY = min(min(l_subclass->GetQ().GetY(), l_subclass->GetY()), minY);
                maxX = max(max(l_subclass->GetQ().GetX(),l_subclass->GetX()), maxX);
                maxY = max(max(l_subclass->GetQ().GetY(),l_subclass->GetY()), maxY);
            }
            else if(r_subclass)
            {
                Rectangulo* r = new Rectangulo(*r_subclass);
                r->SetX(r->GetX()+10);
                r->SetY(r->GetY()+10);
                
                su_modelo->figuras.push_back(r);

                r_subclass = (Rectangulo*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(r_subclass);
                
                minX = min(r_subclass->GetX(), minX);
                minY = min(r_subclass->GetY(), minY);
                maxX = max(r_subclass->GetX()+(int)r_subclass->GetAncho(), maxX);
                maxY = max(r_subclass->GetY()+(int)r_subclass->GetAlto(), maxY);

            }
            else if(img_subclass) {
                ImagenQt* r = new ImagenQt(*img_subclass);
                r->SetX(r->GetX()+10);
                r->SetY(r->GetY()+10);

                su_modelo->figuras.push_back(r);

                img_subclass = (ImagenQt*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(img_subclass);

                minX = min(img_subclass->GetX(), minX);
                minY = min(img_subclass->GetY(), minY);
                maxX = max(img_subclass->GetX()+(int)img_subclass->GetImage().width(), maxX);
                maxY = max(img_subclass->GetY()+(int)img_subclass->GetImage().height(), maxY);
            }
            else if(t_subclass)
            {
                Triangulo* t = new Triangulo(*t_subclass);
                t->SetX(t->GetX()+10);
                t->SetY(t->GetY()+10);
                t->SetP(1,t->GetP(1).GetX()+10,t->GetP(1).GetY()+10);
                t->SetP(2,t->GetP(2).GetX()+10,t->GetP(2).GetY()+10);
                su_modelo->figuras.push_back(t);

                t_subclass = (Triangulo*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(t_subclass);

                minX = min(min(min(t_subclass->GetP(2).GetX(),t_subclass->GetP(1).GetX()),t_subclass->GetX()), minX);
                minY = min(min(min(t_subclass->GetP(2).GetY(),t_subclass->GetP(1).GetY()),t_subclass->GetY()), minY);
                maxX = max(max(max(t_subclass->GetP(2).GetX(),t_subclass->GetP(1).GetX()),t_subclass->GetX()), maxX);
                maxY = max(max(max(t_subclass->GetP(2).GetY(),t_subclass->GetP(1).GetY()),t_subclass->GetY()), maxY);
            }
            else if(c_subclass)
            {
                Circulo* c = new Circulo(*c_subclass);
                c->SetCentro(c->GetX()+10,c->GetY()+10);
                su_modelo->figuras.push_back(c);

                c_subclass = (Circulo*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(c_subclass);
                
                minX = min(c_subclass->GetX(), minX);
                minY = min(c_subclass->GetY(), minY);
                maxX = max(c_subclass->GetX()+(int)c_subclass->GetRadio(), maxX);
                maxY = max(c_subclass->GetY()+(int)c_subclass->GetRadio(), maxY);
            }
            else if(cj_subclass)
            {
                Conjunto* cj = new Conjunto(*cj_subclass);
                
                cj->SetX(cj_subclass->GetX()+10);
                cj->SetY(cj_subclass->GetY()+10);
                for(int i = 0; i < (signed) cj->GetComponentes().size(); i++)
                    cj->GetComponentes()[i]->Move(10,10);
                
                su_modelo->figuras.push_back(cj);

                cj_subclass = (Conjunto*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(cj_subclass);

                minX = min(cj_subclass->GetX(),minX);
                minY = min(cj_subclass->GetY(),minY);
                maxX = max(cj_subclass->GetX()+cj_subclass->GetWidth(), maxX);
                maxY = max(cj_subclass->GetY()+cj_subclass->GetHeight(), maxY);
            }
        }

        Punto p(minX,minY);
        Rectangulo* select = new Rectangulo(p,maxX-minX,maxY-minY);
        select->setSelectionRect();
        su_modelo->figuras.push_back(select);

        pinta(true);
    }

    su_modelo->portapapeles.clear();
}

void
Ventana::clickDup()
{
    clickCopy();
    clickPaste();
}

void
Ventana::clickDelete()
{
    if(!su_modelo->figurasSeleccionadas.empty())
    {
        vector<Primitiva*>::iterator it;
        vector<Primitiva*>::iterator it_select;
        for(it = su_modelo->figuras.begin(); it != su_modelo->figuras.end();it++)
        {
            for(it_select = su_modelo->figurasSeleccionadas.begin(); it_select != su_modelo->figurasSeleccionadas.end();it_select++)
            {
                /* No elimina el elemento, simplemente lo pone a NULL */
                if( *it == *it_select )
                    *it = NULL;
            }
        }
    }
    
    pinta(true);
}

/* Agrupa las figuras seleccionadas */
void
Ventana::clickGroup()
{
    int minX = 10000, minY = 10000, maxX = 0, maxY = 0;
    vector<Primitiva*>::iterator it;
    
    for(it = su_modelo->figurasSeleccionadas.begin(); it != su_modelo->figurasSeleccionadas.end();it++)
    {
        Punto* p_subclass = dynamic_cast<Punto*>(*it);
        Linea* l_subclass = dynamic_cast<Linea*>(*it);
        Rectangulo* r_subclass = dynamic_cast<Rectangulo*>(*it);
        Triangulo* t_subclass = dynamic_cast<Triangulo*>(*it);
        Circulo* c_subclass = dynamic_cast<Circulo*>(*it);
        Conjunto* cj_subclass = dynamic_cast<Conjunto*>(*it);
        ImagenQt* img_subclass = dynamic_cast<ImagenQt*>(*it);

        if(p_subclass)
        {
            minX = min(p_subclass->GetX(), minX);
            minY = min(p_subclass->GetY(), minY);
            maxX = max(p_subclass->GetX(), maxX);
            maxY = max(p_subclass->GetY(), maxY);
        }
        else if(l_subclass)
        {
            minX = min(min(l_subclass->GetX(), l_subclass->GetQ().GetX()),minX);
            minY = min(min(l_subclass->GetQ().GetY(), l_subclass->GetY()), minY);
            maxX = max(max(l_subclass->GetQ().GetX(),l_subclass->GetX()), maxX);
            maxY = max(max(l_subclass->GetQ().GetY(),l_subclass->GetY()), maxY);
        }
        else if(r_subclass)
        {
            minX = min(r_subclass->GetX(), minX);
            minY = min(r_subclass->GetY(), minY);
            maxX = max(r_subclass->GetX()+(int)r_subclass->GetAncho(), maxX);
            maxY = max(r_subclass->GetY()+(int)r_subclass->GetAlto(), maxY);
        }
        else if(t_subclass)
        {
            minX = min(min(min(t_subclass->GetP(2).GetX(),t_subclass->GetP(1).GetX()),t_subclass->GetX()), minX);
            minY = min(min(min(t_subclass->GetP(2).GetY(),t_subclass->GetP(1).GetY()),t_subclass->GetY()), minY);
            maxX = max(max(max(t_subclass->GetP(2).GetX(),t_subclass->GetP(1).GetX()),t_subclass->GetX()), maxX);
            maxY = max(max(max(t_subclass->GetP(2).GetY(),t_subclass->GetP(1).GetY()),t_subclass->GetY()), maxY);
        }
        else if(c_subclass)
        {
            minX = min(c_subclass->GetX(), minX);
            minY = min(c_subclass->GetY(), minY);
            maxX = max(c_subclass->GetX()+(int)c_subclass->GetRadio(), maxX);
            maxY = max(c_subclass->GetY()+(int)c_subclass->GetRadio(), maxY);
        }
        else if(cj_subclass)
        {
            minX = min(cj_subclass->GetX(),minX);
            minY = min(cj_subclass->GetY(),minY);
            maxX = max(cj_subclass->GetX()+cj_subclass->GetWidth(), maxX);
            maxY = max(cj_subclass->GetY()+cj_subclass->GetHeight(), maxY);
        } else if(img_subclass) {
            minX = min(img_subclass->GetX(), minX);
            minY = min(img_subclass->GetY(), minY);
            maxX = max(img_subclass->GetX()+(int)img_subclass->GetImage().width(), maxX);
            maxY = max(img_subclass->GetY()+(int)img_subclass->GetImage().height(), maxY);
        }
    }

    Conjunto* c = new Conjunto(minX,minY,maxX-minX,maxY-minY);
    
    c->Agrupar(su_modelo->figurasSeleccionadas);
    
    su_modelo->figuras.push_back(c);

    clickDelete();
}

void
Ventana::clickUngroup()
{
    for(int i = 0; i < (signed)su_modelo->figurasSeleccionadas.size(); i++)
    {
        Conjunto* cj = dynamic_cast<Conjunto*>(su_modelo->figurasSeleccionadas[i]);
        // se ha seleccionado un conjunto para desagruparlo
        if(cj)
        {
            cj -> Desagrupar(su_modelo->figuras);

            // anulamos el conjunto
            for(int j = 0; j < (signed)su_modelo->figuras.size(); j++)
                if(su_modelo->figuras[i] == cj)
                    su_modelo->figuras[i] = NULL;
        }
    }
}

void
Ventana::clickUndo() {
    if(historial.size() > 0 && historial_actual > 0) {
        historial_actual--;
        
        su_modelo->figuras = historial[historial_actual]->figuras;
        su_modelo->figurasSeleccionadas = historial[historial_actual]->figurasSeleccionadas;
        su_modelo->portapapeles = historial[historial_actual]->portapapeles;

        pinta();
    }
}

void
Ventana::clickRedo() {
    if(historial.size() > 0 && historial_actual < (signed)historial.size() - 1) {
        historial_actual++;

        su_modelo->figuras = historial[historial_actual]->figuras;
        su_modelo->figurasSeleccionadas = historial[historial_actual]->figurasSeleccionadas;
        su_modelo->portapapeles = historial[historial_actual]->portapapeles;

        pinta();
    }
}

void
Ventana::wheelEvent(QWheelEvent* e)
{
    // Si se pulsa control, se rotan las figuras seleccionadas
    if(e->state() == ControlButton)
    {
        if(!su_modelo->figurasSeleccionadas.empty())
        {
            for(int i = 0; i < (signed) su_modelo->figurasSeleccionadas.size(); i++) {
                ImagenQt* img_subclass = dynamic_cast<ImagenQt*>(su_modelo->figurasSeleccionadas[i]);

                if(img_subclass) {
                    int inc;
                    if(e->delta() > 0)
                        inc = 5;
                    else
                        inc = -5;
                    double distOrigenYPunto = sqrt(img_subclass->GetX()*img_subclass->GetX() + img_subclass->GetY()*img_subclass->GetY());
                    double angOrigenYPunto = atan2(img_subclass->GetY(), img_subclass->GetX()) * 180 / PI;

                    double nuevoX = cos((angOrigenYPunto+inc)*PI/180)*distOrigenYPunto,
                            nuevoY = sin((angOrigenYPunto+inc)*PI/180)*distOrigenYPunto;

                    img_subclass->SetX(nuevoX);
                    img_subclass->SetY(nuevoY);
                } else {
                    su_modelo->figurasSeleccionadas[i]->SetGrados(su_modelo->figurasSeleccionadas[i]->GetGrados()+e->delta());
                }
            }
        }
    }
    // Redimensionar las figuras
    else if(e->state() == ShiftButton)
    {
        if(!su_modelo->figurasSeleccionadas.empty())
        {
            for(int i = 0; i < (signed) su_modelo->figurasSeleccionadas.size(); i++)
            {            
                bool aumentar = true;
                if(e->delta() < 0)
                    aumentar = false;

                Linea* l_subclass = dynamic_cast<Linea*>(su_modelo->figurasSeleccionadas[i]);
                Rectangulo* r_subclass = dynamic_cast<Rectangulo*>(su_modelo->figurasSeleccionadas[i]);
                Triangulo* t_subclass = dynamic_cast<Triangulo*>(su_modelo->figurasSeleccionadas[i]);
                Circulo* c_subclass = dynamic_cast<Circulo*>(su_modelo->figurasSeleccionadas[i]);
                ImagenQt* img_subclass = dynamic_cast<ImagenQt*>(su_modelo->figurasSeleccionadas[i]);

                if(l_subclass)
                    l_subclass->Redimensionar(aumentar,true,true);
                else if(r_subclass)
                    r_subclass->Redimensionar(aumentar, true,true);
                else if(t_subclass)
                    t_subclass->Redimensionar(aumentar);
                else if(c_subclass)
                    c_subclass->Redimensionar(aumentar);
                else if(img_subclass)
                    img_subclass->Redimensionar(aumentar,true,true);
            }
        }
    }
    else
    {
        double factor = 1.10;

        if(e->delta() < 0)
            factor = 0.90;

        drawArea->scale(factor,factor);
    }

    if(historial_actual != (signed)historial.size() - 1) {
        while(historial_actual != (signed)historial.size() - 1) {
            historial.pop_back();
        }
    }

    Historial *nuevo = new Historial(su_modelo);
    historial.push_back(nuevo);
    historial_actual = historial.size() - 1;

    pinta();
}

// CLASE SAVEAS

SaveAs::SaveAs(Ventana* v)
{
    win = v;
    QWidget::connect((QObject*) botonAcceptSaveAs_2, SIGNAL(pressed()), SLOT(clickAceptar()));
    QWidget::connect((QObject*) botonCancelSaveAs, SIGNAL(pressed()), SLOT(clickCancelar()));
}

void
SaveAs::clickAceptar()
{
    win->GetModelo()->guardarAFichero(win->GetModelo()->figuras, (string) editSaveAsPath->text().latin1());
    this->close();
}

void
SaveAs::clickCancelar()
{
    this->close();
}